package org.jeecg.modules.business.strategy.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.business.entity.*;
import org.jeecg.modules.business.enums.FeeSubjectType;
import org.jeecg.modules.business.enums.LivingTypeEnum;
import org.jeecg.modules.business.service.IBusLivingLayoutDayPriceService;
import org.jeecg.modules.business.service.IBusOrderFeeService;
import org.jeecg.modules.business.service.IBusRoomsLivingOrderService;
import org.jeecg.modules.business.service.IBusSchemeLayoutDailyPriceService;
import org.jeecg.modules.business.service.impl.BusBookingRoomsServiceImpl;
import org.jeecg.modules.business.strategy.PricingStrategy;
import org.jeecg.modules.business.strategy.util.PricingUtil;
import org.jeecg.modules.rooms.entity.CesAllDayPriceRule;
import org.jeecg.modules.rooms.entity.CesHourRoomRule;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Slf4j
@Component("hourRoomStrategy")
public class HourRoomStrategy  implements PricingStrategy {

    @Resource
    IBusOrderFeeService feeService;

    @Resource
    private BusBookingRoomsServiceImpl bookingRoomsService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    @Resource
    private IBusLivingLayoutDayPriceService livingLayoutDayPriceService;

    @Resource
    IBusSchemeLayoutDailyPriceService schemeLayoutDailyPriceService;

    @Resource
    private IBusRoomsLivingOrderService roomsLivingOrderService;

    @Resource
    PricingUtil pricingUtil;

    @Override
    public void calculateFee(BusRoomsLivingOrder livingOrder, CesAllDayPriceRule cesAllDayPriceRule, List<CesHourRoomRule> hourRoomRuleList) {
        // TODO: 2023/10/24 钟点房超时收费
        Optional<CesHourRoomRule> ruleOptional = hourRoomRuleList.stream().filter(rule -> rule.getId().equals(livingOrder.getHourRoomId())).findFirst();
        ruleOptional.ifPresent(rule -> {
            Calendar nowCalendar = Calendar.getInstance();
            Calendar nextCalendar = Calendar.getInstance();
            nextCalendar.setTime(livingOrder.getDueOutTime());
            Integer overMinutes = Math.round((nowCalendar.getTimeInMillis() - nextCalendar.getTimeInMillis()) / (1000 * 60 ));
            if (overMinutes <= 0){
                return;
            }
            BusBookingRooms bookingroom = bookingRoomsService.getById(livingOrder.getBookingRoomId());
            if (ObjectUtil.isEmpty(bookingroom)){
                log.info("未找到订单{}对应的房间", livingOrder.getId());
                return;
            }
            BusOrderFee fee = pricingUtil.getOverTimeFee(livingOrder, bookingroom);
            // 转为全天房
            if (rule.getLimitTimeTransferAllDay() != 0 && overMinutes > rule.getLimitTimeTransferAllDay()){
                Date arrivalTime = livingOrder.getArrivalTime();
                Calendar arrivalCalendar = Calendar.getInstance();
                arrivalCalendar.setTime(arrivalTime);
                DateTime leaveTime = DateUtil.parse(cesAllDayPriceRule.getLeaveTime(), "HH:mm");
                Calendar leaveCalendar = Calendar.getInstance();
                leaveCalendar.setTime(leaveTime);
                leaveCalendar.set(Calendar.YEAR, arrivalCalendar.get(Calendar.YEAR));
                leaveCalendar.set(Calendar.MONTH, arrivalCalendar.get(Calendar.MONTH));
                leaveCalendar.set(Calendar.DAY_OF_MONTH, arrivalCalendar.get(Calendar.DAY_OF_MONTH));
                Calendar enterCalendar = Calendar.getInstance();
                DateTime enterTime = DateUtil.parse(cesAllDayPriceRule.getEnterTime(), "HH:mm");
                enterCalendar.setTime(enterTime);
                if (arrivalCalendar.get(Calendar.HOUR_OF_DAY) > enterCalendar.get(Calendar.HOUR_OF_DAY)
                        || arrivalCalendar.get(Calendar.HOUR_OF_DAY) == enterCalendar.get(Calendar.HOUR_OF_DAY)
                        && arrivalCalendar.get(Calendar.MINUTE) > enterCalendar.get(Calendar.MINUTE)){
                    // 如果预抵时间在enterTime后面 则预离时间为隔天
                    leaveCalendar.add(Calendar.DAY_OF_YEAR, 1);
                }
                livingOrder.setDueOutTime(leaveCalendar.getTime());
                livingOrder.setLivingType(LivingTypeEnum.ALL_DAY.getKey());
                List<BusOrderFee> busOrderFees = feeService.list(Wrappers.<BusOrderFee>lambdaQuery()
                        .eq(BusOrderFee::getLivingOrderId, livingOrder.getId()).eq(BusOrderFee::getSubjectType, FeeSubjectType.MEI_RI_FANG_FEI.getKey()));
                Optional<BusOrderFee> orderFee = busOrderFees.stream().filter(e -> !e.getIsOverTime()).findFirst();

                // 修改房费为全天房费
                orderFee.ifPresent(e -> {
                    BusLivingLayoutDayPrice dayPrice = livingLayoutDayPriceService.getOne(Wrappers.<BusLivingLayoutDayPrice>lambdaQuery()
                            .eq(BusLivingLayoutDayPrice::getLivingOrderId, livingOrder.getId())
                            .eq(BusLivingLayoutDayPrice::getDayTime, DateUtils.formatDate(livingOrder.getArrivalTime())).last("limit 1"));
                    BigDecimal money = schemeLayoutDailyPriceService.getOneDayPrice(bookingroom.getRoomLayoutId(), livingOrder, new Date());
                    e.setMoney(money);
                    feeService.updateById(e);
                    if (dayPrice != null){
                        dayPrice.setPrice(money);
                        livingLayoutDayPriceService.updateById(dayPrice);
                    }
                });
                // 删除超时收费项
                Optional<BusOrderFee> overTimeFee = busOrderFees.stream().filter(BusOrderFee::getIsOverTime).findFirst();
                overTimeFee.ifPresent(e -> {
                    feeService.removeById(e.getId());
                });
                roomsLivingOrderService.updateById(livingOrder);
                leaveCalendar.add(Calendar.MINUTE, Integer.parseInt(cesAllDayPriceRule.getDayTime()));
                redisTemplate.opsForZSet().remove("overTimerOrder",livingOrder.getId());
                redisTemplate.opsForZSet().add("overTimerOrder",livingOrder.getId(),leaveCalendar.getTimeInMillis());
                return;
            }
            //已经超时的 不足时间
            Integer minutesDiff = overMinutes % rule.getExceedTime();
            // 超出 超时时间 的数量
            Integer minutesDiffNum = (int) Math.floor(overMinutes / rule.getExceedTime());
            // 不足时间 数量
            Integer moreThenMinuteDiffNum = (int) Math.floor(minutesDiff / rule.getNotReachExceedTime());
            // 加上下一次不足时间 >= 超出时间，用超出时间
            if (minutesDiff + rule.getNotReachExceedTime() > rule.getExceedTime()){
                Integer newOverTime = rule.getExceedTime() * (minutesDiffNum + 1);
                nextCalendar.add(Calendar.MINUTE, newOverTime);
            }else {
                nextCalendar.add(Calendar.MINUTE, rule.getNotReachExceedTime());
            }
            log.info("钟点房{}今日超时分钟{}，超时时间数量{}，不足时间数量{}",livingOrder.getId(),overMinutes,minutesDiffNum,moreThenMinuteDiffNum);
            BigDecimal money = rule.getExceedPay().multiply(BigDecimal.valueOf(minutesDiffNum))
                    .add(rule.getNotReachExceedTimePay().multiply(BigDecimal.valueOf(moreThenMinuteDiffNum)));
            // 有上限，且金额超过当前上限
            if (rule.getMaxExtraPay().compareTo(new BigDecimal(0)) != 0 && rule.getMaxExtraPay().compareTo(money) < 0){
                money = rule.getMaxExtraPay();
            }
            fee.setMoney(money);
            fee.setDayTime(nowCalendar.getTime());
            redisTemplate.opsForZSet().remove("overTimerOrder",livingOrder.getId());

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            log.info(format.format(nextCalendar.getTime()));
            redisTemplate.opsForZSet().add("overTimerOrder",livingOrder.getId(),nextCalendar.getTimeInMillis());
            // 添加超时房费
            feeService.saveOrUpdate(fee);
        });
    }
}
